TypeScript入门之申明文件 |
您所在的位置:网站首页 › ts 声明文件 › TypeScript入门之申明文件 |
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情 简介申明文件在我们平时开发中用到的并不多,但是当我们要开源一个库的时候,就需要我们写申明文件了。 那什么是申明文件?申明文件又有什么作用?以及怎样定义申明文件呢? 什么是申明文件通常我们会把声明语句放到一个单独的文件(xxx.d.ts)中,这就是声明文件,以 .d.ts 为后缀。 申明文件的作用虽然 TypeScript 已经逐渐进入主流,但是市面上大部分库还是以 JavaScript 编写的,这个时候由于库没有像 TS 一样定义类型,因此需要一个声明文件来帮助库的使用者来获取库的类型提示。 说到这里小伙伴可能有疑问了,我们学习了接口、类、类型别名不都是用来定义类型的吗?怎么又会出来个申明文件呢? 接口、类、类型别名是用来定义类型别名的。但是每次都需要我们引入然后给变量定义类型。但是申明文件只需要我们申明一次,在项目中不需要再引入和定义类型就能全局直接使用。 我们来看个例子: 我们在new Vue的时候,如果不定义好Vue class是会报错的。并且每次我们new Vue的时候都需要引入class Vue。 // type.js interface VueOption { el: string; data: any; } export class Vue { options: VueOption; constructor(options: VueOption) { this.options = options; } }使用的时候我们必须import进来。 // main.js import {Vue} from "./type.js" const app = new Vue({ el: "#app", data: { message: "hello world", }, });我们改造下,使用申明文件 // index.d.ts interface VueOption { el: string; data: any; } declare class Vue { options: VueOption; constructor(options: VueOption); }有了申明文件,项目全局不需要引入就能直接使用了。 // main.js const app = new Vue({ el: "#app", data: { message: "hello world", }, });这样就不会报错了。 使用申明文件的好处是我们只需要定义一次就能全局使用。相对接口、类、类型别名来说是更方便的。 发布声明文件我们为一个开源库编写了声明文件后应该如何发布? 目前有两个选择: 将什么文件向开源库提 PR,声明文件与源码放在一起,作为第一方声明。 发布到 DefinitelyTyped,作为第三方声明文件。 第一方声明如果是手动写的声明文件,下面三种方式都能被正确的识别: 给 package.json 中的 types 或 typings 字段指定一个类型声明文件地址。 在项目根目录下,编写一个 index.d.ts 文件,该文件会被自动读取。 针对入口文件(package.json 中的 main 字段指定的入口文件),编写一个同名不同后缀的 .d.ts 文件,这样也会被自动读取。 第一种方式是给 package.json 中的 types 或 typings 字段指定一个类型声明文件地址。比如: { "name": "foo", "version": "1.0.0", "main": "lib/index.js", "types": "foo.d.ts", }指定了 types 为 foo.d.ts 之后,导入此库的时候,就会去找 foo.d.ts 作为此库的类型声明文件了。 typings 与 types 一样,只是另一种写法。 如果没有指定 types 或 typings,那么就会在根目录下寻找 index.d.ts 文件,将它视为此库的类型声明文件。 如果没有找到 index.d.ts 文件,那么就会寻找入口文件(package.json 中的 main 字段指定的入口文件)是否存在对应同名不同后缀的 .d.ts 文件。 比如 package.json 是这样时: { "name": "foo", "version": "1.0.0", "main": "lib/index.js", }就会先识别 package.json 中是否存在 types 或 typings 字段。发现不存在,那么就会寻找是否存在 index.d.ts 文件。如果还是不存在,那么就会寻找是否存在 lib/index.d.ts 文件。假如说连 lib/index.d.ts 都不存在的话,就会被认为是一个没有提供类型声明文件的库了。 将声明文件发布到DefinitelyTyped如果我们是在给别人的仓库添加类型声明文件,但原作者不愿意合并 pull request,那么就需要将声明文件发布到 @types 下。 与普通的 npm 模块不同,@types 是统一由 DefinitelyTyped 管理的。要将声明文件发布到 @types 下,就需要给 DefinitelyTyped 创建一个 pull-request,其中包含了类型声明文件,测试代码,以及 tsconfig.json 等。 pull-request 需要符合它们的规范,并且通过测试,才能被合并,稍后就会被自动发布到 @types 下。 介绍了申明文件的作用以及发布申明文件的两种方法,我们再来说说怎么写申明文件。 写申明文件前面介绍的DefinitelyTyped,它定义了市面上主流的 JavaScript 库的 d.ts,我们可以在 Type Search里面搜索我们需要的申明文件,然后使用 npm 安装这些 d.ts。 比如我们要安装 JQuery 的 d.ts: npm install @types/jquery -save当然,如果使我们自己写的库,需要申明文件,这就需要我们手动来写申明文件了。写申明文件有两种方式。 自动生成如果库的源码本身就是由 ts 写的,那么在使用 tsc 脚本将 ts 编译为 js 的时候,添加 declaration 选项,就可以同时也生成 .d.ts 声明文件了. 我们可以在命令行中添加 --declaration(简写 -d),或者在 tsconfig.json 中添加 declaration 选项。 这里以 tsconfig.json 为例: { "compilerOptions": { "module": "commonjs", "outDir": "lib", "declaration": true, } }上例中我们添加了 outDir 选项,将 ts 文件的编译结果输出到 lib 目录下,然后添加了 declaration 选项,设置为 true,表示将会由 ts 文件自动生成同名的 .d.ts 声明文件,也会输出到 lib 目录下。 当然如果我们的库是js写的就没办法自动生成了,就只能手写了。 手动写关键字 declare 表示声明的意思,我们可以用它来做出各种声明: declare var 声明全局变量 declare function 声明全局方法 declare class 声明全局类 declare enum 声明全局枚举类型 declare namespace 声明(含有子属性的)全局对象 interface 和 type 声明全局类型 声明变量declare var/let/const,全局变量的声明可以说是最简单的了,虽然 var/let/const 都可以使用的,但是通常情况下全局变量是不允许改动的,大多数情况下还是以 const 为主: // src/jQuery.d.ts declare const jQuery: (selector: string) => any; 声明函数declare function 用来声明全局函数: // src/jQuery.d.ts declare function jQuery(selector: string): any; 声明类declare class 用于声明全局类 // src/Person.d.ts declare class Person { name: string; constructor(name: string); say(): string; } 声明枚举declare enum 是于声明全局枚举类型 // src/Directions.d.ts declare enum Directions { Up, Down, Left, Right } 声明命名空间declare namespace,命名空间虽然在日常开发中已经不常见了,但是在 d.ts 文件编写时还是很常见的,它用来表示全局变量是一个对象,包含很多子属性。 比如 jQuery 是全局对象,而其包含一个 jQuery.ajax 用于处理 ajax 请求,这个时候命名空间就派上用场了: // src/jQuery.d.ts declare namespace jQuery { function ajax(url: string, settings?: any): void; } 声明interface 和 type除了全局变量之外,可能有一些类型我们也希望能暴露出来。 在类型声明文件中,我们可以直接使用 interface 或 type 来声明一个全局的接口或类型: // src/jQuery.d.ts interface AjaxSettings { method?: 'GET' | 'POST' data?: any; } declare namespace jQuery { function ajax(url: string, settings?: AjaxSettings): void; } 声明合并假如 jQuery 既是一个函数,可以直接被调用 jQuery('#foo'),又是一个对象,拥有子属性 jQuery.ajax()(事实确实如此),那么我们可以组合多个声明语句,它们会不冲突的合并起来: // src/jQuery.d.ts declare function jQuery(selector: string): any; declare namespace jQuery { function ajax(url: string, settings?: any): void; } // src/index.ts jQuery('#foo'); jQuery.ajax('/api/get_something'); 系列文章TypeScript入门之环境搭建 TypeScript入门之数据类型 TypeScript入门之函数 TypeScript入门之接口 TypeScript入门之类 TypeScript入门之类型推断、类型断言、双重断言、非空断言、确定赋值断言、类型守卫、类型别名 TypeScript入门之泛型 TypeScript入门之装饰器 TypeScript入门之模块与命名空间 TypeScript入门之申明文件 TypeScript入门之常用内置工具类型 TypeScript入门之配置文件 后记感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力! |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |